home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / BBS-Archive / Comm / AmiTCP30b2.lha / src / amitcp / kern / uipc_mbuf.c < prev    next >
C/C++ Source or Header  |  1993-08-12  |  22KB  |  907 lines

  1. RCS_ID_C = "$Id: uipc_mbuf.c,v 1.18 1993/06/04 11:16:15 jraja Exp $";
  2. /*
  3.  * Copyright (c) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>
  4.  *                    Helsinki University of Technology, Finland.
  5.  *                    All rights reserved.
  6.  *
  7.  * Last modified: Fri Jun  4 00:36:45 1993 jraja
  8.  *
  9.  * HISTORY
  10.  * $Log: uipc_mbuf.c,v $
  11.  * Revision 1.18  1993/06/04  11:16:15  jraja
  12.  * Fixes for first public release.
  13.  *
  14.  * Revision 1.17  1993/05/29  20:57:23  jraja
  15.  * Added function mb_read_stats() to return mbuf type specific statistics.
  16.  *
  17.  * Revision 1.16  1993/05/16  15:20:25  ppessi
  18.  * Fixed bug with cluster allocation.
  19.  *
  20.  * Revision 1.16  1993/05/16  15:20:25  ppessi
  21.  * Fixed bug with cluster allocation.
  22.  *
  23.  * Revision 1.15  93/05/04  12:52:25  12:52:25  jraja (Jarno Tapio Rajahalme)
  24.  * Fixed default values of the configuration variables.
  25.  * 
  26.  * Revision 1.14  93/04/25  02:59:37  02:59:37  jraja (Jarno Tapio Rajahalme)
  27.  * Added some comments.
  28.  * 
  29.  * Revision 1.13  93/04/24  22:19:41  22:19:41  jraja (Jarno Tapio Rajahalme)
  30.  * Removed MBTYPES, moved configurable variables to a structure (mbconf),
  31.  * removed nmbufs and nmbclusters (already in mbstat), moved mbufmemsize to
  32.  * mbstat (as m_memused), added configuration notify function 
  33.  * mb_check_conf() to validate configurable variables,
  34.  * added checks for maximum memory usage,
  35.  * removed m_retryhdr(), since m_retry() is already called by MGETHDR,
  36.  * removed all USECLUSTERS (now using clusters always.
  37.  * 
  38.  * Revision 1.12  93/04/23  02:26:28  02:26:28  ppessi (Pekka Pessi)
  39.  * Added some configureable parameters
  40.  * 
  41.  * Revision 1.11  93/04/13  22:31:51  22:31:51  jraja (Jarno Tapio Rajahalme)
  42.  * Added #ifdef USECLUSTERS ... #endif to compile without.
  43.  * 
  44.  * Revision 1.10  93/04/06  15:16:04  15:16:04  jraja (Jarno Tapio Rajahalme)
  45.  * Changed spl function return value storage to spl_t,
  46.  * changed bcopys and bzeros to aligned and/or const when possible,
  47.  * added inclusion of conf.h to every .c file.
  48.  * 
  49.  * Revision 1.9  93/04/02  01:08:17  01:08:17  jraja (Jarno Tapio Rajahalme)
  50.  * Implemented clusters.
  51.  * Updated memory allocation.
  52.  * Added memHeader structure to keep account of allocated memory.
  53.  * 
  54.  * Revision 1.8  93/03/05  03:26:21  03:26:21  ppessi (Pekka Pessi)
  55.  * Compiles with SASC. Initial test version.
  56.  * 
  57.  * Revision 1.7  93/03/04  09:55:46  09:55:46  jraja (Jarno Tapio Rajahalme)
  58.  * Fixed includes.
  59.  * 
  60.  * Revision 1.6  93/03/03  19:59:29  19:59:29  jraja (Jarno Tapio Rajahalme)
  61.  * Added static initializers to globals.
  62.  * 
  63.  * Revision 1.5  93/03/03  19:20:43  19:20:43  jraja (Jarno Tapio Rajahalme)
  64.  * Moved some definitions from sys/mbuf.h to here.
  65.  * 
  66.  * Revision 1.4  93/02/24  12:55:20  12:55:20  jraja (Jarno Tapio Rajahalme)
  67.  * Changed init to remember if initialized.
  68.  * 
  69.  * Revision 1.3  93/01/06  19:24:53  19:24:53  jraja (Jarno Tapio Rajahalme)
  70.  * Ported this for AmigaOS. Added function mbdeinit(), which is used to free
  71.  * memory allocated by mbuf subsystem.
  72.  * Alse commented all memory cluster related stuff with #ifdef USECLUSTERS.
  73.  * 
  74.  * Revision 1.2  92/11/20  15:14:25  15:14:25  jraja (Jarno Tapio Rajahalme)
  75.  * Added #ifndef AMITCP's to make this compile.
  76.  * 
  77.  * Revision 1.1  92/11/19  12:07:15  12:07:15  jraja (Jarno Tapio Rajahalme)
  78.  * Initial revision
  79.  */
  80.  
  81. /* 
  82.  * Mach Operating System
  83.  * Copyright (c) 1992 Carnegie Mellon University
  84.  * All Rights Reserved.
  85.  * 
  86.  * Permission to use, copy, modify and distribute this software and its
  87.  * documentation is hereby granted, provided that both the copyright
  88.  * notice and this permission notice appear in all copies of the
  89.  * software, derivative works or modified versions, and any portions
  90.  * thereof, and that both notices appear in supporting documentation.
  91.  * 
  92.  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
  93.  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  94.  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  95.  * 
  96.  * Carnegie Mellon requests users of this software to return to
  97.  * 
  98.  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
  99.  *  School of Computer Science
  100.  *  Carnegie Mellon University
  101.  *  Pittsburgh PA 15213-3890
  102.  * 
  103.  * any improvements or extensions that they make and grant Carnegie Mellon 
  104.  * the rights to redistribute these changes.
  105.  */
  106. /*
  107.  * HISTORY
  108.  * Log:    uipc_mbuf.c,v
  109.  * Revision 2.2  92/06/25  17:25:22  mrt
  110.  *     Preallocate mbufs in a chunk.
  111.  *     [92/06/24            rwd]
  112.  * 
  113.  * Revision 2.1  92/04/21  17:12:59  rwd
  114.  * BSDSS
  115.  * 
  116.  *
  117.  */
  118.  
  119. /*
  120.  * Copyright (c) 1982, 1986, 1988, 1991 Regents of the University of California.
  121.  * All rights reserved.
  122.  *
  123.  * Redistribution and use in source and binary forms, with or without
  124.  * modification, are permitted provided that the following conditions
  125.  * are met:
  126.  * 1. Redistributions of source code must retain the above copyright
  127.  *    notice, this list of conditions and the following disclaimer.
  128.  * 2. Redistributions in binary form must reproduce the above copyright
  129.  *    notice, this list of conditions and the following disclaimer in the
  130.  *    documentation and/or other materials provided with the distribution.
  131.  * 3. All advertising materials mentioning features or use of this software
  132.  *    must display the following acknowledgement:
  133.  *    This product includes software developed by the University of
  134.  *    California, Berkeley and its contributors.
  135.  * 4. Neither the name of the University nor the names of its contributors
  136.  *    may be used to endorse or promote products derived from this software
  137.  *    without specific prior written permission.
  138.  *
  139.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  140.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  141.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  142.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  143.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  144.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  145.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  146.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  147.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  148.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  149.  * SUCH DAMAGE.
  150.  *
  151.  *    @(#)uipc_mbuf.c    7.19 (Berkeley) 4/20/91
  152.  */
  153.  
  154. #include <conf.h>
  155.  
  156. #include <sys/param.h>
  157. #include <sys/malloc.h>
  158. #include <sys/mbuf.h>
  159. #include <sys/kernel.h>
  160. #include <sys/syslog.h>
  161. #include <sys/systm.h>
  162. #include <sys/domain.h>
  163. #include <sys/protosw.h>
  164. #include <sys/synch.h>
  165.  
  166. #include <kern/amiga_includes.h>
  167.  
  168. #include <dos/rdargs.h>
  169.  
  170. /*
  171.  * Configuration information.
  172.  */
  173. struct mbconf mbconf = {
  174.   2,                        /* # of mbuf chunks to allocate initially */
  175.   64,                /* # of mbufs to allocate at a time */
  176.   4,                /* # of clusters to allocate at a time */
  177.   256,                /* maximum memory to use (in kilobytes) */
  178.   2048                /* size of the mbuf cluster */
  179. };
  180.  
  181. /*
  182.  * List of free mbufs. Access to this list is protected by splimp()
  183.  */
  184. struct mbuf *mfree = NULL;
  185.  
  186. struct    mbstat mbstat = { 0 };
  187.  
  188. struct    mcluster *mclfree = NULL;
  189.  
  190. int    max_linkhdr = 0;        /* largest link-level header */
  191. int    max_protohdr = 0;        /* largest protocol header */
  192. int    max_hdr = 0;            /* largest link+protocol header */
  193. int    max_datalen = 0;        /* MHLEN - max_hdr */
  194.  
  195. /*
  196.  * Header structure that is placed at the start of every allocated memory 
  197.  * region to be freed on deinit. All memory alloctions are thus 
  198.  * sizeof(memHeader) larger and the data pointer is set past this header
  199.  * before used. These headers are linked together and the mbufmem pointer 
  200.  * holds the pointer to the start of the list.
  201.  */
  202. struct memHeader {
  203.   struct memHeader *next;
  204.   ULONG             size;
  205. };
  206.  
  207. static struct memHeader *mbufmem = NULL;
  208.  
  209. static BOOL initialized = FALSE;
  210.  
  211. LONG mb_read_stats(struct CSource *args, UBYTE **errstrp, struct CSource *res)
  212. {
  213.   int i, total = 0;
  214.   UBYTE *p = res->CS_Buffer;
  215.  
  216.   for(i = 0; i < MTCOUNT; i++) {
  217.     p += sprintf(p, "%ld ", mbstat.m_mtypes[i]);
  218.     total += mbstat.m_mtypes[i];
  219.   }
  220.   p += sprintf(p, "%ld", total);
  221.  
  222.   res->CS_CurChr = p - res->CS_Buffer;
  223.   return RETURN_OK;
  224. }
  225.  
  226. int 
  227. mb_check_conf(void *dp, LONG newvalue)
  228. {
  229.   if ((u_long *)dp == &mbconf.initial_mbuf_chunks) {
  230.     if (newvalue > 0)
  231.       return TRUE;
  232.   }
  233.   else 
  234.   if (dp == &mbconf.mbufchunk) {
  235.     if (newvalue >= 32)
  236.       return TRUE;
  237.   }
  238.   else 
  239.   if (dp == &mbconf.clusterchunk) {
  240.     if (newvalue > 0)
  241.       return TRUE;
  242.   }
  243.   else 
  244.   if (dp == &mbconf.maxmem) {
  245.     if (newvalue > 32)        /* kilobytes */
  246.       return TRUE;
  247.   }
  248.   else 
  249.   if (dp == &mbconf.mclbytes) {
  250.     if (newvalue >= MINCLSIZE)
  251.       return TRUE;
  252.   }
  253.   
  254.   return FALSE;
  255.  
  256. /*
  257.  * mbinit() must be called before any other mbuf related function (exept the
  258.  * mb_check_conf() which is called at configuration time). This
  259.  * allocates memory from the system in one big chunk. This memory will not be
  260.  * freed until AMITCP/IP is shut down.
  261.  */
  262.  
  263. BOOL
  264. mbinit(void)
  265. {
  266.   spl_t s;
  267.  
  268.   /*
  269.    * Return success if already initialized
  270.    */
  271.   if (initialized)
  272.     return TRUE;
  273.  
  274.   s = splimp();
  275.   /*
  276.    * Initialize the list headers to NULL
  277.    */
  278.   mfree = NULL;
  279.   mclfree = NULL;
  280.  
  281.   /*
  282.    * Preallocate some mbufs and mbuf clusters.
  283.    */
  284.   initialized = 
  285.     (m_alloc(mbconf.initial_mbuf_chunks * mbconf.mbufchunk, M_WAIT)
  286.      && m_clalloc(mbconf.clusterchunk, M_WAIT));
  287.  
  288.   splx(s);
  289.   
  290.   if (!initialized) {
  291.     log(LOG_ERR, "mbinit: Failed to allocate memory.");
  292.     mbdeinit();
  293.   }
  294.   return (initialized);
  295. }
  296.  
  297. /*
  298.  * Free all memory allocated by mbuf subsystem. This must be the last mbuf
  299.  * related function called. (Implying that NO mbuf allocations should be done
  300.  * concurrently with this!)
  301.  *
  302.  * This is new function to AMITCP/IP.
  303.  */
  304. void
  305. mbdeinit(void)
  306. {
  307.   struct memHeader *next;
  308.  
  309.   /*
  310.    * free all memory chunks
  311.    */
  312.   while (mbufmem) {
  313.     next = mbufmem->next;
  314.     mbstat.m_memused -= mbufmem->size;
  315.     FreeMem(mbufmem, mbufmem->size);
  316.     mbufmem = next;
  317.   }
  318.   initialized = FALSE;
  319. }
  320.  
  321. /*
  322.  * Allocate memory for mbufs.
  323.  * and place on the mbuf free list.
  324.  * The canwait argument is currently ignored.
  325.  *
  326.  * MUST be called at splimp!
  327.  */
  328. BOOL
  329. m_alloc(int howmany, int canwait)
  330. {
  331.  /*
  332.   * Note that mbufs must be aligned on MSIZE boundary
  333.   * for dtom to work correctly. This is archieved by allocating size for one 
  334.   * additional mbuf per chunk so that given memory can be aligned properly.
  335.   */ 
  336.   struct mbuf *m;
  337.   struct memHeader *mh;
  338.   ULONG  size;
  339.  
  340.   size = MSIZE * (howmany + 1) + sizeof(struct memHeader);
  341.  
  342.   /*
  343.    * check if allowed to allocate more
  344.    */
  345.   if (mbstat.m_memused + size > mbconf.maxmem * 1024) {
  346.     log(LOG_ERR, "m_alloc: max amount of memory already used (%ld bytes).",
  347.     mbstat.m_memused);
  348.     return FALSE;
  349.   }
  350.  
  351.   mh = AllocMem(size, MEMF_PUBLIC);    /* public since used from interrupts */
  352.   if (mh == NULL) {
  353.     log(LOG_ERR, "m_alloc: Cannot allocate memory for mbufs.");
  354.     return FALSE;
  355.   }
  356.  
  357.   /*
  358.    * initialize the memHeader and link it to the chain of allocated memory 
  359.    * blocks
  360.    */
  361.   mbstat.m_memused += size;        /* add to the total */
  362.   mh->size = size;
  363.   mh->next = mbufmem;
  364.   mbufmem = mh;
  365.   mh++;                /* pass by the memHeader */
  366.  
  367.   /*
  368.    * update the statistics
  369.    */
  370.   mbstat.m_mbufs += howmany;
  371.  
  372.   /*
  373.    * link mbufs into the free list
  374.    */
  375.   m = dtom(((caddr_t)mh) + MSIZE - 1); /* correctly aligned mbuf pointer */
  376.   while(howmany--) {
  377.     m->m_next = mfree;
  378.     mfree = m++;
  379.   }
  380.   return TRUE;
  381. }  
  382.  
  383. /*
  384.  * Allocate some number of mbuf clusters
  385.  * and place on cluster free list.
  386.  * The canwait argument is currently ignored.
  387.  * MUST be called at splimp.
  388.  */
  389. BOOL
  390. m_clalloc(int ncl, int canwait)
  391. {
  392.   struct memHeader *mh;
  393.   struct mcluster *p;
  394.   ULONG  size;
  395.   short  i;
  396.  
  397.   /*
  398.    * struct mcluster has variable length buffer so its size is not calculated
  399.    * in sizeof(struct mcluster). The size of the buffer is mbconf.mclbytes.
  400.    * Each memory block allocated is prepended by the memHeader, so size
  401.    * must be allocted for it, too.
  402.    */
  403.   size = ncl * (sizeof(struct mcluster) + mbconf.mclbytes)
  404.     + sizeof(struct memHeader);
  405.  
  406.   /*
  407.    * check if allowed to allocate more
  408.    */
  409.   if (mbstat.m_memused + size > mbconf.maxmem * 1024) {
  410.     log(LOG_ERR, "m_clalloc: max amount of memory already used (%ld bytes).",
  411.     mbstat.m_memused);
  412.     return FALSE;
  413.   }
  414.  
  415.   mh = AllocMem(size, MEMF_PUBLIC); /* public since used from interrupts */
  416.   if (mh == NULL) {
  417.     log(LOG_ERR, "m_clalloc: Cannot allocate memory for mbuf clusters");
  418.     return FALSE;
  419.   }
  420.   /*
  421.    * initialize the memHeader and link it to the chain of allocated memory 
  422.    * blocks
  423.    */
  424.   mbstat.m_memused += size;
  425.   mh->size = size;
  426.   mh->next = mbufmem;
  427.   mbufmem = mh;
  428.   mh++;                /* pass by the memHeader */
  429.   /*
  430.    * link clusters to the free list
  431.    */
  432.   for (i = 0, p = (struct mcluster *)mh; 
  433.        i < ncl; 
  434.        i++, p = (struct mcluster*)((char *)(p + 1) + mbconf.mclbytes)) {
  435.     p->mcl.mcl_next = mclfree;
  436.     mclfree = p;
  437.     mbstat.m_clfree++;
  438.   }
  439.   mbstat.m_clusters += ncl;
  440.   
  441.   return TRUE;
  442. }
  443.  
  444. /*
  445.  * When MGET failes, ask protocols to free space when short of memory,
  446.  * then re-attempt to allocate an mbuf.
  447.  *
  448.  * Allocate more memory for mbufs if there still are no mbufs left 
  449.  *
  450.  * MUST be called at splimp.
  451.  */
  452. struct mbuf *
  453. m_retry(int canwait, int type)
  454. {
  455.   register struct mbuf *m;
  456.  
  457.   m_reclaim();
  458.  
  459.   /*
  460.    * Try to allocate more memory if still no free mbufs
  461.    */
  462.   if (!mfree)
  463.     m_alloc(mbconf.mbufchunk, canwait);
  464.   
  465. #define m_retry(i, t)    /*mbstat.m_drops++,*/NULL
  466.   MGET(m, canwait, type);
  467. #undef m_retry
  468.   return (m);
  469. }
  470.  
  471. void
  472. m_reclaim()
  473. {
  474.     register struct domain *dp;
  475.     register struct protosw *pr;
  476.     spl_t s = splimp();
  477.  
  478.     for (dp = domains; dp; dp = dp->dom_next)
  479.         for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
  480.             if (pr->pr_drain)
  481.                 (*pr->pr_drain)();
  482.     splx(s);
  483.     mbstat.m_drain++;
  484. }
  485.  
  486. /*
  487.  * Space allocation routines.
  488.  * These are also available as macros
  489.  * for critical paths.
  490.  */
  491. struct mbuf *
  492. m_get(canwait, type)
  493.     int canwait, type;
  494. {
  495.     register struct mbuf *m;
  496.  
  497.     MGET(m, canwait, type);
  498.     return (m);
  499. }
  500.  
  501. struct mbuf *
  502. m_gethdr(canwait, type)
  503.     int canwait, type;
  504. {
  505.     register struct mbuf *m;
  506.  
  507.     MGETHDR(m, canwait, type);
  508.     return (m);
  509. }
  510.  
  511. struct mbuf *
  512. m_getclr(canwait, type)
  513.     int canwait, type;
  514. {
  515.     register struct mbuf *m;
  516.  
  517.     MGET(m, canwait, type);
  518.     if (m == 0)
  519.         return (0);
  520.     aligned_bzero_const(mtod(m, caddr_t), MLEN);
  521.     return (m);
  522. }
  523.  
  524. struct mbuf *
  525. m_free(m)
  526.     struct mbuf *m;
  527. {
  528.     register struct mbuf *n;
  529.  
  530.     MFREE(m, n);
  531.     return (n);
  532. }
  533.  
  534. void
  535. m_freem(m)
  536.     register struct mbuf *m;
  537. {
  538.     register struct mbuf *n;
  539.  
  540.     if (m == NULL)
  541.         return;
  542.     do {
  543.         MFREE(m, n);
  544.     } while (m = n);
  545. }
  546.  
  547. /*
  548.  * Mbuffer utility routines.
  549.  */
  550.  
  551. /*
  552.  * Lesser-used path for M_PREPEND:
  553.  * allocate new mbuf to prepend to chain,
  554.  * copy junk along.
  555.  */
  556. struct mbuf *
  557. m_prepend(m, len, canwait)
  558.     register struct mbuf *m;
  559.     int len, canwait;
  560. {
  561.     struct mbuf *mn;
  562.  
  563.     MGET(mn, canwait, m->m_type);
  564.     if (mn == NULL) {
  565.         m_freem(m);
  566.         return (NULL);
  567.     }
  568.     if (m->m_flags & M_PKTHDR) {
  569.         M_COPY_PKTHDR(mn, m);
  570.         m->m_flags &= ~M_PKTHDR;
  571.     }
  572.     mn->m_next = m;
  573.     m = mn;
  574.     if (len < MHLEN)
  575.         MH_ALIGN(m, len);
  576.     m->m_len = len;
  577.     return (m);
  578. }
  579.  
  580. /*
  581.  * Make a copy of an mbuf chain starting "off0" bytes from the beginning,
  582.  * continuing for "len" bytes.  If len is M_COPYALL, copy to end of mbuf.
  583.  * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller.
  584.  */
  585. int MCFail;
  586.  
  587. struct mbuf *
  588. m_copym(m, off0, len, wait)
  589.     register struct mbuf *m;
  590.     int off0, wait;
  591.     register int len;
  592. {
  593.     register struct mbuf *n, **np;
  594.     register int off = off0;
  595.     struct mbuf *top = NULL;
  596.     int copyhdr = 0;
  597.  
  598.     if (off < 0 || len < 0) {
  599.       log(LOG_ERR, "m_copym: Bad arguments");
  600.       goto nospace;
  601.     }
  602.     if (off == 0 && m->m_flags & M_PKTHDR)
  603.         copyhdr = 1;
  604.     /*
  605.      * find first mbuf to copy data from
  606.      */
  607.     while (off > 0) {
  608.         if (m == 0) {
  609.           log(LOG_ERR, "m_copym: short mbuf chain");
  610.           goto nospace;
  611.         }
  612.         if (off < m->m_len)
  613.             break;
  614.         off -= m->m_len;
  615.         m = m->m_next;
  616.     }
  617.     np = ⊤
  618.     while (len > 0) {
  619.         if (m == 0) {
  620.             if (len != M_COPYALL) {
  621.               log(LOG_ERR, "m_copym: short mbuf chain");
  622.               goto nospace;
  623.             }
  624.             break;
  625.         }
  626.         MGET(n, wait, m->m_type);
  627.         *np = n;
  628.         if (n == 0)
  629.             goto nospace;
  630.         if (copyhdr) {
  631.             M_COPY_PKTHDR(n, m);
  632.             if (len == M_COPYALL)
  633.                 n->m_pkthdr.len -= off0;
  634.             else
  635.                 n->m_pkthdr.len = len;
  636.             copyhdr = 0;
  637.         }
  638.         n->m_len = MIN(len, m->m_len - off);
  639.  
  640.         if (m->m_flags & M_EXT) {
  641.             n->m_data = m->m_data + off;
  642.             m->m_ext.ext_buf->mcl.mcl_refcnt++;
  643.             n->m_ext = m->m_ext;
  644.             n->m_flags |= M_EXT;
  645.         } else
  646.             bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
  647.                 (unsigned)n->m_len);
  648.         if (len != M_COPYALL)
  649.             len -= n->m_len;
  650.         off = 0;
  651.         m = m->m_next;
  652.         np = &n->m_next;
  653.     }
  654.     if (top == 0)
  655.         MCFail++;
  656.     return (top);
  657. nospace:
  658.     m_freem(top);
  659.     MCFail++;
  660.     return NULL;
  661. }
  662.  
  663. /*
  664.  * Copy data from an mbuf chain starting "off" bytes from the beginning,
  665.  * continuing for "len" bytes, into the indicated buffer.
  666.  */
  667. void
  668. m_copydata(m, off, len, cp)
  669.     register struct mbuf *m;
  670.     register int off;
  671.     register int len;
  672.     caddr_t cp;
  673. {
  674.     register unsigned count;
  675.  
  676.     if (off < 0 || len < 0) {
  677.       log(LOG_ERR, "m_copydata: bad arguments");
  678.       return;
  679.     }
  680.     while (off > 0) {
  681.         if (m == 0) {
  682.           log(LOG_ERR, "m_copydata: short mbuf chain to copy from");
  683.           return;
  684.         }
  685.         if (off < m->m_len)
  686.             break;
  687.         off -= m->m_len;
  688.         m = m->m_next;
  689.     }
  690.     while (len > 0) {
  691.         if (m == 0) {
  692.           log(LOG_ERR, "m_copydata: short mbuf chain to copy from");
  693.           return;
  694.         }
  695.         count = MIN(m->m_len - off, len);
  696.         bcopy(mtod(m, caddr_t) + off, cp, count);
  697.         len -= count;
  698.         cp += count;
  699.         off = 0;
  700.         m = m->m_next;
  701.     }
  702. }
  703.  
  704. /*
  705.  * Concatenate mbuf chain n to m.
  706.  * Both chains must be of the same type (e.g. MT_DATA).
  707.  * Any m_pkthdr is not updated.
  708.  */
  709. void
  710. m_cat(m, n)
  711.     register struct mbuf *m, *n;
  712. {
  713.     while (m->m_next)
  714.         m = m->m_next;
  715.     while (n) {
  716.         if (m->m_flags & M_EXT ||
  717.             m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) {
  718.             /* just join the two chains */
  719.             m->m_next = n;
  720.             return;
  721.         }
  722.         /* splat the data from one into the other */
  723.         bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
  724.             (u_int)n->m_len);
  725.         m->m_len += n->m_len;
  726.         n = m_free(n);
  727.     }
  728. }
  729.  
  730. void
  731. m_adj(struct mbuf *mp, int req_len)
  732. {
  733.     register int len = req_len;
  734.     register struct mbuf *m;
  735.     register count;
  736.  
  737.     if ((m = mp) == NULL)
  738.         return;
  739.     if (len >= 0) {
  740.         /*
  741.          * Trim from head.
  742.          */
  743.         while (m != NULL && len > 0) {
  744.             if (m->m_len <= len) {
  745.                 len -= m->m_len;
  746.                 m->m_len = 0;
  747.                 m = m->m_next;
  748.             } else {
  749.                 m->m_len -= len;
  750.                 m->m_data += len;
  751.                 len = 0;
  752.             }
  753.         }
  754.         m = mp;
  755.         if (mp->m_flags & M_PKTHDR)
  756.             m->m_pkthdr.len -= (req_len - len);
  757.     } else {
  758.         /*
  759.          * Trim from tail.  Scan the mbuf chain,
  760.          * calculating its length and finding the last mbuf.
  761.          * If the adjustment only affects this mbuf, then just
  762.          * adjust and return.  Otherwise, rescan and truncate
  763.          * after the remaining size.
  764.          */
  765.         len = -len;
  766.         count = 0;
  767.         for (;;) {
  768.             count += m->m_len;
  769.             if (m->m_next == (struct mbuf *)0)
  770.                 break;
  771.             m = m->m_next;
  772.         }
  773.         if (m->m_len >= len) {
  774.             m->m_len -= len;
  775.             if ((mp = m)->m_flags & M_PKTHDR)
  776.                 m->m_pkthdr.len -= len;
  777.             return;
  778.         }
  779.         count -= len;
  780.         if (count < 0)
  781.             count = 0;
  782.         /*
  783.          * Correct length for chain is "count".
  784.          * Find the mbuf with last data, adjust its length,
  785.          * and toss data from remaining mbufs on chain.
  786.          */
  787.         m = mp;
  788.         if (m->m_flags & M_PKTHDR)
  789.             m->m_pkthdr.len = count;
  790.         for (; m; m = m->m_next) {
  791.             if (m->m_len >= count) {
  792.                 m->m_len = count;
  793.                 break;
  794.             }
  795.             count -= m->m_len;
  796.         }
  797.         while (m = m->m_next)
  798.             m->m_len = 0;
  799.     }
  800. }
  801.  
  802. /*
  803.  * Rearrange an mbuf chain so that len bytes from the beginning are
  804.  * contiguous and in the data area of an mbuf (so that mtod and dtom
  805.  * will work for a structure of size len). Note that resulting
  806.  * structure is assumed to get properly aligned. This will happen only if
  807.  * there is no odd-length data before the structure. Fortunately all
  808.  * headers are before any data in the packet and are of even length.
  809.  * Returns the resulting mbuf chain on success, frees it and returns
  810.  * null on failure. If there is room, it will add up to max_protohdr-len
  811.  * extra bytes to the contiguous region in an attempt to avoid being
  812.  * called next time.
  813.  */
  814. int MPFail;
  815.  
  816. struct mbuf *
  817. m_pullup(n, len)
  818.     register struct mbuf *n;
  819.     int len;
  820. {
  821.     register struct mbuf *m;
  822.     register int count;
  823.     int space;
  824.  
  825.     /*
  826.      * If first mbuf has no cluster, and has room for len bytes
  827.      * without shifting current data, pullup into it,
  828.      * otherwise allocate a new mbuf to prepend to the chain.
  829.      */
  830.     if ((n->m_flags & M_EXT) == 0 &&
  831.         n->m_data + len < &n->m_dat[MLEN] && n->m_next) {
  832.         if (n->m_len >= len)
  833.             return (n);
  834.         m = n;            /* pullup to */
  835.         n = n->m_next;        /* pullup from */
  836.         len -= m->m_len;     /* pullup length */
  837.     } else {
  838.         if (len > MHLEN)
  839.             goto bad;
  840.         MGET(m, M_DONTWAIT, n->m_type);
  841.         if (m == 0)
  842.             goto bad;
  843.         m->m_len = 0;
  844.         if (n->m_flags & M_PKTHDR) {
  845.             M_COPY_PKTHDR(m, n);
  846.             n->m_flags &= ~M_PKTHDR;
  847.         }
  848.     }
  849.     space = &m->m_dat[MLEN] - (m->m_data + m->m_len);
  850.     do {
  851.         count = min(min(max(len, max_protohdr), space), n->m_len);
  852.         bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
  853.           (unsigned)count);
  854.         len -= count;
  855.         m->m_len += count;
  856.         n->m_len -= count;
  857.         space -= count;
  858.         if (n->m_len)
  859.             n->m_data += count;
  860.         else
  861.             n = m_free(n);
  862.     } while (len > 0 && n);
  863.     if (len > 0) {
  864.         (void) m_free(m);
  865.         goto bad;
  866.     }
  867.     m->m_next = n;
  868.     return (m);
  869. bad:
  870.     m_freem(n);
  871.     MPFail++;
  872.     return (0);
  873. }
  874.  
  875. #if 0                /* not needed (yet), DO NOT DELETE! */
  876. /*
  877.  * Allocate a "funny" mbuf, that is, one whose data is owned by someone else.
  878.  */
  879. struct mbuf *
  880. mclgetx(fun, arg, addr, len, wait)
  881.         void (*fun)();
  882.         int arg, len, wait;
  883.         caddr_t addr;
  884. {
  885.         register struct mbuf *m;
  886.  
  887.         MGETHDR(m, wait, MT_DATA);
  888.         if (m == 0)
  889.                 return (0);
  890.         m->m_data = addr ;
  891.         m->m_len = len;
  892.         m->m_ext.ext_free = fun;
  893.         m->m_ext.ext_size = len;
  894.         m->m_ext.ext_buf = (caddr_t)arg;
  895.         m->m_flags |= M_EXT;
  896.  
  897.         return (m);
  898. }
  899.  
  900. void mcl_free_routine(buf, size)
  901.     char *buf;
  902.     int size;
  903. {
  904. }
  905. #endif /* 0 */
  906.